#include "realelement.h"


#include <QDebug>

RealElement::RealElement()
{
    this->delay = 0;
    this->defaultSignal = -1;
    this->performed = false;
}

RealElement::~RealElement(){}

//Ищем выходной пин
void RealElement::init(const QString& configPath)
{
    ConfiguredElement::init(configPath);
    int j = 0;
    while ((j < this->pins.count()) &&
          (this->pins[j]->type != PinType_Out))
        j++;
    if (j < this->pins.count())
        this->outPIN = this->pins[j];
    else
        throw OutputNotFound(this);
    this->lastTics.resize(pins.count());

    for (int i = 0; i < this->pins.count(); i++)
        this->lastTics[i] = -1;

}

//Вычислить сигнал
signed char RealElement::computeSignal()
{
    /*Значение ищется по таблице истинности*/
    //Индекс в таблице истинности
    uint index = 0;
    //Степени двойки
    uint bi = 1;
    //Количество входных пинов
    int count = pins.count() - 1;
    for (int i = 0; i < count; i++)
    {
        index += pins.at(i)->signal * bi;
        bi *= 2;
    }
    return valuesTable.at(index);
}

//Выполнить работу
bool RealElement::performAction()
{
    bool action = false;
    if(pins.count() > 0)
    {
        int count = 0;
        int notDefinedCount = 0;

        for(int i = 0; i < this->pins.count(); i++)
        {
            if(pins[i]->type == PinType_In)
            {
                if(pins[i]->ticTime <= lastTics[i])
                    count++;
                if(pins[i]->signal < 0)
                    notDefinedCount++;
            }
        }

        if ((count == 0) && (notDefinedCount == 0))
        {
            for(int pi = 0; pi<pins.count(); pi++)
                lastTics[pi] = pins[pi]->ticTime;
            signed char currentSignal = computeSignal();
            signalQueue.enqueue(currentSignal);
            ticTime++;
            performed = true;
            action = true;
        }
    }
    return action;
}

//Отправить результирующий сигнал
bool RealElement::sendSignals()
{
    if(this->performed)
    {
        if(this->signalQueue.count() > 0)
        {
            signed char res = this->signalQueue.dequeue();
            if (res != -1)
            {
                this->outPIN->send(res);
                return true;
            }
        }
        this->performed = false;
    }
    return false;
}

void RealElement::refresh()
{
    CircuitElement::refresh();
    this->signalQueue.clear();
    for(uint i = 0; i < this->delay; i++)
        this->signalQueue.enqueue(this->defaultSignal);
    for(int i = 0; i<pins.count(); i++)
        this->lastTics[i] = -1;
}

void RealElement::initProps(const QDomNode &additionals)
{
    QString valuesTableAttr = additionals.namedItem("table").attributes().
                           namedItem("value").nodeValue();
    QString point = "";
    setDelay( additionals.namedItem("delay").attributes().
             namedItem("value").nodeValue().toInt() );
    for (int i = 0; i < valuesTableAttr.count(); i++)
    {
        point = valuesTableAttr.at(i);
        valuesTable.append( point.toInt() );
    }
}

void RealElement::saveProps(QDomNode &additionals)
{
    QString valuesString = "";
    for (int i = 0; i < this->valuesTable.count(); i++)
    {
        valuesString += QString::number(this->valuesTable.at(i));
    }
    XmlHelper::addSimpleXmlNode(additionals, "delay", QString::number(delay));
    XmlHelper::addSimpleXmlNode(additionals, "table", valuesString);
}

uint RealElement::getDelay()
{
    return delay;
}

void RealElement::setDelay(uint delay)
{
    delay = delay;
    refresh();
}

signed char RealElement::getDefaultSignal()
{
    return defaultSignal;
}

void RealElement::setDefaultSignal(signed char signal)
{
    this->defaultSignal = signal;
    refresh();
}
